<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8" />
    <title>PCM 16kHz 16-bit WebSocket 传输示例</title>
</head>
<body>
    <h1>PCM 16k 16-bit WebSocket 传输示例</h1>
    <button id="startBtn">开始录音</button>
    <button id="stopBtn" disabled>停止录音</button>
    <pre id="result"></pre>

<script>
    const startBtn = document.getElementById("startBtn");
    const stopBtn = document.getElementById("stopBtn");
    const resultBox = document.getElementById("result");

    let audioContext;
    let processor;
    let source;
    let socket;

    // 重采样：48kHz -> 16kHz
    function downsampleBuffer(buffer, inputSampleRate, outputSampleRate) {
        if (outputSampleRate === inputSampleRate) {
            return buffer;
        }
        const sampleRateRatio = inputSampleRate / outputSampleRate;
        const newLength = Math.round(buffer.length / sampleRateRatio);
        const result = new Float32Array(newLength);
        let offsetResult = 0;
        let offsetBuffer = 0;
        while (offsetResult < result.length) {
            const nextOffsetBuffer = Math.round((offsetResult + 1) * sampleRateRatio);
            // 取平均值防止失真
            let accum = 0, count = 0;
            for (let i = offsetBuffer; i < nextOffsetBuffer && i < buffer.length; i++) {
                accum += buffer[i];
                count++;
            }
            result[offsetResult] = accum / count;
            offsetResult++;
            offsetBuffer = nextOffsetBuffer;
        }
        return result;
    }

    // Float32 [-1,1] 转 Int16 [-32768,32767]
    function convertFloat32ToInt16(buffer) {
        const l = buffer.length;
        const result = new Int16Array(l);
        for (let i = 0; i < l; i++) {
            let s = Math.max(-1, Math.min(1, buffer[i]));
            result[i] = s < 0 ? s * 0x8000 : s * 0x7FFF;
        }
        return result;
    }

    startBtn.onclick = async () => {
        socket = new WebSocket("ws://127.0.0.1:8000/ws/speech");

        socket.onopen = () => {
            console.log("WebSocket 已连接");
        };

        socket.onmessage = (event) => {
            resultBox.textContent += event.data + "\n";
        };

        socket.onclose = () => {
            console.log("WebSocket 已关闭");
        };

        const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
        audioContext = new (window.AudioContext || window.webkitAudioContext)();
        const inputSampleRate = audioContext.sampleRate;
        source = audioContext.createMediaStreamSource(stream);

        processor = audioContext.createScriptProcessor(4096, 1, 1);

        processor.onaudioprocess = (e) => {
            const inputData = e.inputBuffer.getChannelData(0);
            // 重采样到16kHz
            const downsampledBuffer = downsampleBuffer(inputData, inputSampleRate, 16000);
            // 转换为Int16
            const int16Buffer = convertFloat32ToInt16(downsampledBuffer);
            if (socket.readyState === WebSocket.OPEN) {
                // 发送原始PCM二进制数据
                socket.send(int16Buffer.buffer);
            }
        };

        source.connect(processor);
        processor.connect(audioContext.destination);

        startBtn.disabled = true;
        stopBtn.disabled = false;
    };

    stopBtn.onclick = () => {
        if (processor) {
            processor.disconnect();
            processor = null;
        }
        if (source) {
            source.disconnect();
            source = null;
        }
        if (audioContext) {
            audioContext.close();
            audioContext = null;
        }
        if (socket && socket.readyState === WebSocket.OPEN) {
            socket.close();
        }
        startBtn.disabled = false;
        stopBtn.disabled = true;
    };
</script>
</body>
</html>

<!-- <!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>语音识别测试</title>
</head>
<body>
    <h1>语音识别 WebSocket 测试</h1>
    <button id="startBtn">开始录音</button>
    <button id="stopBtn" disabled>停止录音</button>
    <div>
        <h2>识别结果：</h2>
        <pre id="result"></pre>
    </div>

    <script>
        const startBtn = document.getElementById("startBtn");
        const stopBtn = document.getElementById("stopBtn");
        const resultBox = document.getElementById("result");

        let mediaRecorder;
        let socket;

        startBtn.onclick = async () => {
            // 建立 WebSocket 连接
            socket = new WebSocket("ws://127.0.0.1:8000/ws/speech");

            socket.onopen = () => {
                console.log("WebSocket 已连接");
            };

            socket.onmessage = (event) => {
                resultBox.textContent += event.data + "\n";
            };

            socket.onclose = () => {
                console.log("WebSocket 已关闭");
            };

            const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
            mediaRecorder = new MediaRecorder(stream);

            mediaRecorder.ondataavailable = async (e) => {
                if (socket.readyState === WebSocket.OPEN) {
                    socket.send(e.data);
                }
            };

            mediaRecorder.start(250); // 每250ms分段发送

            startBtn.disabled = true;
            stopBtn.disabled = false;
        };

        stopBtn.onclick = () => {
            mediaRecorder.stop();
            socket.close();

            startBtn.disabled = false;
            stopBtn.disabled = true;
        };
    </script>
</body>
</html> -->
